/**
 * @file   Time.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2014-04-19
 * @brief  DON data type object: Time
 *
 * Copyright 2014  Djuro Drljaca (djurodrljaca@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DON/Core/DataType/Time.h>
#include <DON/Core/DataType/UInt32.h>
#include <QtCore/QByteArray>
#include <QtCore/QTime>

using namespace DON::Core::DataType;

class Time::Private
{
public:
    Private()
        : value(QTime())
    { }

    QTime value;
};

Time::Time()
    : AbstractDataType(),
      d(new Private())
{
}

Time::Time(const Time &other)
    : AbstractDataType(),
      d(new Private())
{
    d->value = other.d->value;
}

Time::~Time()
{
    delete d;
}

Time & Time::operator=(const Time &other)
{
    d->value = other.d->value;

    return *this;
}

AbstractDataType * Time::clone() const
{
    return new Time(*this);
}

DataType Time::getDataType() const
{
    return DataType_Time;
}

QTime Time::getValue() const
{
    return d->value;
}

void Time::setValue(const QTime &value)
{
    d->value = value;
}

bool Time::fromBinary(const QByteArray &data, const int startIndex, int *size)
{
    QTime value;
    bool success = false;

    const quint32 timeValue = UInt32::fromBinary(data, startIndex, &success);

    if (success)
    {
        const int microsecond = static_cast<int>(timeValue & 0x1F);
        const int millisecond = static_cast<int>((timeValue >> 5) & 0x03FF);
        const int second = static_cast<int>((timeValue >> 15) & 0x3F);
        const int minute = static_cast<int>((timeValue >> 21) & 0x3F);
        const int hour = static_cast<int>((timeValue >> 27) & 0x1F);

        value.setHMS(hour, minute, second, millisecond);

        if (microsecond >= 16)
        {
            value.addMSecs(1);
        }

        success = value.isValid();
    }

    if (success)
    {
        d->value = value;

        if (size != NULL)
        {
            *size = 4;
        }
    }

    return success;
}

QByteArray Time::toBinary() const
{
    QByteArray data;
    const QTime &value = d->value;

    if (value.isValid())
    {
        const int microsecond = 0;
        const int millisecond = value.msec();
        const int second = value.second();
        const int minute = value.minute();
        const int hour = value.hour();

        quint32 timeValue = static_cast<quint32>(microsecond) |
                            (static_cast<quint32>(millisecond) << 5) |
                            (static_cast<quint32>(second) << 15) |
                            (static_cast<quint32>(minute) << 21) |
                            (static_cast<quint32>(hour) << 27);

        data.append(UInt32::toBinary(timeValue));
    }

    return data;
}

Time * Time::fromAbstractDataType(AbstractDataType *instance)
{
    Time *outputInstance = NULL;

    if (instance != NULL)
    {
        if (instance->getDataType() == DataType_Time)
        {
            outputInstance = static_cast<Time *>(instance);
        }
    }

    return outputInstance;
}
